]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
screenshot: Add API to get PNG stream from a texture
authorIvan Molodetskikh <yalterz@gmail.com>
Sat, 15 Jan 2022 15:20:51 +0000 (18:20 +0300)
committerMarge Bot <marge-bot@gnome.org>
Thu, 27 Jan 2022 22:25:42 +0000 (22:25 +0000)
With the new screenshot UI we're introducing, we'll be capturing all
screenshots to textures on the GPU at first, and then create a PNG
stream from those textures at a later point. This will allow us to
present screenshots immediately to the user so they can inspect them and
select the right area before actually saving them to disk.

As a first step to make this work, introduce a new ShellScreenshot API
that writes an existing CoglTexture to a PNG output stream:
shell_screenshot_composite_to_stream ()

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1954>

src/shell-screenshot.c
src/shell-screenshot.h

index 100429f2172b910aca6a01c789dc31d991f60498..34494185a6758b16ff3ccc9bcd7ce5abe6fe1323 100644 (file)
@@ -804,6 +804,124 @@ shell_screenshot_pick_color_finish (ShellScreenshot  *screenshot,
 #undef INDEX_G
 #undef INDEX_B
 
+static void
+composite_to_stream_on_png_saved (GObject      *source,
+                                  GAsyncResult *result,
+                                  gpointer      user_data)
+{
+  GTask *task = G_TASK (user_data);
+  GError *error = NULL;
+
+  if (!gdk_pixbuf_save_to_stream_finish (result, &error))
+    g_task_return_error (task, error);
+  else
+    g_task_return_boolean (task, TRUE);
+
+  g_object_unref (task);
+}
+
+/**
+ * shell_screenshot_composite_to_stream:
+ * @texture: the source texture
+ * @x: x coordinate of the rectangle
+ * @y: y coordinate of the rectangle
+ * @width: width of the rectangle, or -1 to use the full texture
+ * @height: height of the rectangle, or -1 to use the full texture
+ * @stream: the stream to write the PNG image into
+ * @callback: (scope async): function to call returning success or failure
+ * @user_data: the data to pass to callback function
+ *
+ * Composite a rectangle defined by x, y, width, height from the texture to a
+ * pixbuf and write it as a PNG image into the stream.
+ *
+ */
+void
+shell_screenshot_composite_to_stream (CoglTexture         *texture,
+                                      int                  x,
+                                      int                  y,
+                                      int                  width,
+                                      int                  height,
+                                      GOutputStream       *stream,
+                                      GAsyncReadyCallback  callback,
+                                      gpointer             user_data)
+{
+  CoglContext *ctx;
+  CoglTexture *sub_texture;
+  cairo_surface_t *surface;
+  g_autoptr (GTask) task = NULL;
+  g_autoptr (GdkPixbuf) pixbuf = NULL;
+  g_autofree char *creation_time = NULL;
+  g_autoptr (GDateTime) date_time = NULL;
+
+  task = g_task_new (NULL, NULL, callback, user_data);
+  g_task_set_source_tag (task, shell_screenshot_composite_to_stream);
+
+  if (width == -1 || height == -1)
+    {
+      x = 0;
+      y = 0;
+      width = cogl_texture_get_width (texture);
+      height = cogl_texture_get_height (texture);
+    }
+
+  ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
+  sub_texture = cogl_sub_texture_new (ctx, texture, x, y, width, height);
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                        cogl_texture_get_width (sub_texture),
+                                        cogl_texture_get_height (sub_texture));
+
+  cogl_texture_get_data (sub_texture, CLUTTER_CAIRO_FORMAT_ARGB32,
+                         cairo_image_surface_get_stride (surface),
+                         cairo_image_surface_get_data (surface));
+  cairo_surface_mark_dirty (surface);
+
+  cogl_object_unref (sub_texture);
+
+  // Save to an image.
+  pixbuf = gdk_pixbuf_get_from_surface (surface,
+                                        0, 0,
+                                        cairo_image_surface_get_width (surface),
+                                        cairo_image_surface_get_height (surface));
+  cairo_surface_destroy (surface);
+
+  date_time = g_date_time_new_now_local ();
+  creation_time = g_date_time_format (date_time, "%c");
+
+  if (!creation_time)
+    creation_time = g_date_time_format (date_time, "%FT%T%z");
+
+  gdk_pixbuf_save_to_stream_async (pixbuf, stream, "png", NULL,
+                                   composite_to_stream_on_png_saved,
+                                   g_steal_pointer (&task),
+                                   "tEXt::Software", "gnome-screenshot",
+                                   "tEXt::Creation Time", creation_time,
+                                   NULL);
+}
+
+/**
+ * shell_screenshot_composite_to_stream_finish:
+ * @result: the #GAsyncResult that was provided to the callback
+ * @error: #GError for error reporting
+ *
+ * Finish the asynchronous operation started by
+ * shell_screenshot_composite_to_stream () and obtain its result.
+ *
+ * Returns: whether the operation was successful
+ *
+ */
+gboolean
+shell_screenshot_composite_to_stream_finish (GAsyncResult  *result,
+                                             GError       **error)
+{
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
+  g_return_val_if_fail (g_async_result_is_tagged (result,
+                                                  shell_screenshot_composite_to_stream),
+                        FALSE);
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
 ShellScreenshot *
 shell_screenshot_new (void)
 {
index 18c6667e1ba3f8b1fb7df0422d2f3ec06ca3fe6d..838e910a7ef2d8cdb323c10dba5febe27e09e55f 100644 (file)
@@ -60,4 +60,15 @@ gboolean shell_screenshot_pick_color_finish (ShellScreenshot      *screenshot,
                                              ClutterColor         *color,
                                              GError              **error);
 
+void shell_screenshot_composite_to_stream (CoglTexture         *texture,
+                                           int                  x,
+                                           int                  y,
+                                           int                  width,
+                                           int                  height,
+                                           GOutputStream       *stream,
+                                           GAsyncReadyCallback  callback,
+                                           gpointer             user_data);
+gboolean shell_screenshot_composite_to_stream_finish (GAsyncResult  *result,
+                                                      GError       **error);
+
 #endif /* ___SHELL_SCREENSHOT_H__ */